<?php

namespace App\Models\Traits;

use App\Models\User;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis;
use Rainsens\Dinglog\Facades\Dinglog;
use Brick\Math\RoundingMode;
use Carbon\Carbon;

trait HasUserCache
{
	public static function sMyPayCodeTryCacheKey($id): string
	{
		return "user_{$id}_pay_code_try";
	}

	public static function sInfoCacheKey($id): string
	{
		return "user_{$id}_info";
	}

	public static function sGetCache($id)
	{
		if (! Redis::exists(self::sInfoCacheKey($id))) {
			if ($user = self::find($id)) {
				$user->addToCache();
				$user->setRank();
				Log::debug("User: {$user->id} first cached");
			}
		}
		return Redis::hGetAll(self::sInfoCacheKey($id));
	}



	/*==================================================================================================================*/


	public function myPayCodeTryCacheKey(): string
	{
		return self::sMyPayCodeTryCacheKey($this->id);
	}

	public function infoCacheKey(): string
	{
		return self::sInfoCacheKey($this->id);
	}

	public function cacheFields(): array
	{
        $user = $this;
        $parent = "";
        if($user->parent_id){

        	$parent = User::find($user->parent_id);
        }
      
		return [
			'id' => $user->id,
			'parent_id' => $user->parent_id,
			'is_valid_vip' => !empty($user->isValidVip()) ? $user->isValidVip() :  '0',
			'balances' => $user->balances,
            'unlocked_gold_subsidies' => $user->unlockedGoldSubsidies(),
			'grade' => $user->grade,
			'invite_code' => $user->invite_code,
			//'invite_string' => $user->inviteString(),

            'gold_wastes_money' => $user->myAllGoldWastesMoney(),
            'has_gold_wastes_order_applied' => $user->hasGoldWastesOrderApplied(),
            'has_gold_wastes_subsidy_applied' => $user->hasGoldWastesSubsidyApplied(),

			'name' => $user->name ?? '',
			'nickname' => $user->nickname ?? '',
			'phone' => $user->phone ?? '',
			'signature' => $user->signature ?? '',
			'avatar_url' => img_path($user->avatar),
			'planLocate'=>$user->planLocate,
			'gender' => $user->gender ?? '',
			'birthday' => $user->birthday ?? '',
			'dividend_all' => $user->dividend_all,
			'dividend_day' => $user->dividend_day,

			'is_pay_code_set' => $user->isPayCodeSet(),

			'is_phone_bound' => $user->isPhoneBound(),
			'is_weixin_bound' => $user->isWeixinBound(),
			'is_weimini_bound' => $user->isWeiminiBound(),
			'is_alipay_bound' => $user->isAlipayBound(),
			'is_freelance_auth' => $user->isFreelanceAuth(),
			'wx_nickname' => $user->wx_nickname ?? '',
			'wx_headimgurl' => $user->wx_headimgurl ?? '',
			'alipay_nickname' => $user->alipay_nickname ?? '',
			'alipay_avatar' => $user->alipay_avatar ?? '',
			'alipay_user_no' => $user->alipay_user_no ?? '',

			'parent_phone' =>$parent ? $parent->phone : '',
			'parent_name' => $parent ? $parent->name : '',
			'parent_avatar_url' =>  $parent ? img_path($parent->avatar) : '',
			'parent_qq_account'=>  $parent ? $parent->qq_account : '',
			'parent_wechat_account'=>  $parent ? $parent->wechat_account : '',
			'parent_contact_phone' => $parent ? $parent->contact_phone : '',

			'team_number' => $user->myTeam()->count(),

			'user_today_prize_count' => $user->prizes()->whereDate("created_at",Carbon::now())->count(),
			'user_sign_in_count' => $user->signins()->where("is_consecutive",1)->count(),
			'has_sign_in' => $user->signins()->where("date",Carbon::today())->exists() ? 1 : 0,
			'has_share' => $user->shareRecords()->exists() ? 1 : 0,

			'dividend_settle_rewards' => $user->dividendSettleRewards(),

			'vip_cards' => $user->vip_cards,
			'vip_expired_at' => $user->vip_expired_at,
			'rewards' => $user->rewards,
			'is_test' => $user->is_test,
			'has_command' => $user->has_command,

			'auto_upgrade_needs_children' => (int)cs('sale')->auto_upgrade_needs_children,
			'auto_upteam_needs_children' => (int)cs('sale')->auto_upteam_needs_children,
			
			
			'wx_image' => $user->defaultWxpay() ? $user->defaultWxpay()->wx_image : '',
			'alipay_real_name' => $user->defaultAlipay() ? $user->defaultAlipay()->alipay_real_name : '',
			'alipay_number' => $user->defaultAlipay() ? $user->defaultAlipay()->alipay_number : '',
			'real_name' => $user->real_name ? $user->real_name : '',
			'cert_number' => $user->cert_number ? $user->cert_number : '',
			'bank_name' => $user->bank_name ? $user->bank_name : '',
			'bank_abbr' => $user->bank_abbr ? $user->bank_abbr : '',
			'contact_phone' => $user->contact_phone ?? '',
			'children_num' => $this->myDownChildrenNum(),
			'children_dividend_reward' =>  (string)$user->myDownChildrenReward(),
			'is_auth' =>  $user->isAuthRealName(),
			'wechat_account' => $user->wechat_account,
			'qq_account' => $user->qq_account,
			'is_stop' => $user->is_stop,
			'created_at' => (string)$user->created_at
			
		];
	}

	public function addToCache()
	{
		$data = $this->cacheFields();

		//Redis::transaction(function () use ($data) {
			Redis::hMSet($this->infoCacheKey(), $data);
			Redis::expire($this->infoCacheKey(), cache_time());
		//});

			
	}

	public function addToRank()
	{
		$yesterdayAllMoney = (string)big_decimal($this->myDownChildrenRewardYesterday())->plus($this->resoldProfitYesterday());
		$dividendAllMoney = (string)big_decimal($this->resoldProfitAll())->plus($this->myDownChildrenReward());

		Redis::zAdd('yesterday_rank',$yesterdayAllMoney,$this->id);
		Redis::zAdd('dividend_rank',$dividendAllMoney,$this->id);

		Redis::hMset($this->infoCacheKey(), ['dividend_all_money'=>$dividendAllMoney,'yesterday_all_money'=>$yesterdayAllMoney]);
	}

	public function setRank()
	{
		$yesterdayRankCache = Redis::Zrevrank("yesterday_rank",$this->id);
		$dividentRankCache = Redis::Zrevrank("dividend_rank",$this->id);
     	Dinglog::text("设置rank");
     	if($yesterdayRankCache >= 0 && $this->is_gold_intern == 1){
     		$yesterdayRankCache = $yesterdayRankCache + 1;

     	}else{
     		$yesterdayRankCache = 0;

     	}
        

     	if($yesterdayRankCache > 100){

     		$yesterdayRankCache = 0;
     	}

     	if($dividentRankCache >= 0 && $this->is_gold_intern == 1){
     		$dividentRankCache = $dividentRankCache + 1;

     	}else{
     		$dividentRankCache = 0;

     	}
        

     	if($dividentRankCache > 100){

     		$dividentRankCache = 0;
     	}
     	$yesterdayAllMoney = (string)big_decimal($this->myDownChildrenRewardYesterday())->plus($this->resoldProfitYesterday());
		$dividendAllMoney = (string)big_decimal($this->resoldProfitAll())->plus($this->myDownChildrenReward());
		Redis::hMset($this->infoCacheKey(), ['yesterday_rank'=>$yesterdayRankCache,'dividend_rank'=>$dividentRankCache,'dividend_all_money'=>$dividendAllMoney,'yesterday_all_money'=>$yesterdayAllMoney]);
	}


	public function getCachePay()
	{
		if (! Redis::exists($this->infoCacheKey())) {
			$this->addToCache();
			$this->setRank();
		}
		$data = [
			'wx_image' => Redis::hGet($this->infoCacheKey(),'wx_image'),
			'alipay_real_name' => Redis::hGet($this->infoCacheKey(),'alipay_real_name'),
			'alipay_number' => Redis::hGet($this->infoCacheKey(),'alipay_number'),
			'real_name' => Redis::hGet($this->infoCacheKey(),'real_name'),
			'bank_name' => Redis::hGet($this->infoCacheKey(),'bank_name'),
			'bank_abbr' => Redis::hGet($this->infoCacheKey(),'bank_abbr'),
			'phone' => Redis::hGet($this->infoCacheKey(),'contact_phone'),
			'cert_number' => Redis::hGet($this->infoCacheKey(),'cert_number'),
			'avatar_url' =>  Redis::hGet($this->infoCacheKey(),'avatar_url'),
			'user_name' =>  Redis::hGet($this->infoCacheKey(),'name'),
		];
		
		return $data;
	}


	public function getBeansCache()
	{
		if (! Redis::exists($this->infoCacheKey())) {
			$this->addToCache();
			$this->setRank();
		}
		
		
		return Redis::hGet($this->infoCacheKey(),'gold_beans');
	}

	public function setGoldBeans($todayBeans)
	{
		$userBeans =Redis::hGet($this->infoCacheKey(),'gold_beans');
		$beans = big_decimal($userBeans)->minus($todayBeans);

		return Redis::hMset($this->infoCacheKey(),['gold_beans'=>(string)$beans]);
	}

	public function getCache()
	{
		
		//if (! Redis::exists($this->infoCacheKey())) {

			$this->addToCache();
			
			//$this->setRank();
		//}
		return Redis::hGetAll($this->infoCacheKey());
	}


	public function setNickName($nickname){
		Redis::hMSet($this->infoCacheKey(), ['nickname'=>$nickname]);

	}
	public function delFromCache()
	{
		Redis::del($this->infoCacheKey());
	}

	public function todayBonusTop100FromCache()
	{
		$key = "today_bonus_rank";
		return Cache::remember($key, 60, function () {
			return $this->dayBonusTop100();
		});
	}

	public function allBonusTop100FromCache()
	{
		$key = "all_bonus_rank";
		return Cache::remember($key, 60, function () {
			return $this->allBonusTop100();
		});
	}

	public function dayBonusRank($index = 0): array
	{
		$users = collect();

		$limit = $index + 9;
		$index = $index > 0 ? $index+1 : $index;

		$top100 = $this->todayBonusTop100FromCache();

		$mineId = $this->id;
		$mineRank = $top100->contains($mineId) ? $top100->search($mineId)+1 : 0;

		foreach ($top100 as $k => $id) {
			if ($k >= $index and $k <= $limit) {
				$users->push(self::sGetCache($id));
			}
		}

		return ['mine' => (int)$mineRank, 'day' => $users];
	}

	public function allBonusRank($index = 0): array
	{
		$users = collect();

		$limit = $index + 9;
		$index = $index > 0 ? $index+1 : $index;

		$top100 = $this->allBonusTop100FromCache();

		$mineId = $this->id;
		$mineRank = $top100->contains($mineId) ? $top100->search($mineId)+1 : 0;

		foreach ($top100 as $k => $id) {
			if ($k >= $index and $k <= $limit) {
				$users->push(self::sGetCache($id));
			}
		}

		return ['mine' => (int)$mineRank, 'all' => $users];
	}

	public function myTeamMembers()
	{
		$scope = request('scope');

		$key = url()->full();
		$key = "{$key}-user-{$this->id}-{$scope}-teams";

		return Cache::remember($key, 1, function () use ($scope) {
			return $this->myDownOneChildren($scope)
				->orderBy('parent_id')
				->orderByDesc('id')
				->paginate();
		});
	}

	public function myPayCodeTryCache(): int
	{
		$key = $this->myPayCodeTryCacheKey();

		if ($try = Redis::get($key)) {
			return (int)$try;
		} else {
			Redis::set($key, 0);
			$try = Redis::get($key);
			return (int)$try;
		}
	}

	public function leftPayCodeTryAfterError(): int
	{
		$payCodeTry = $this->myPayCodeTryCache() + 1;
		$payCodeTry = $payCodeTry <= 3 ? $payCodeTry : 3;
		Redis::set($this->myPayCodeTryCacheKey(), $payCodeTry);
		$leftChance = 3 - $payCodeTry;
		return $leftChance;
	}

	public function resetPayCodeTry()
	{
		$try = $this->myPayCodeTryCache();

		if ($try <= 0) return;

		Redis::set($this->myPayCodeTryCacheKey(), 0);
	}
}
